package com.kede.api.level.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kede.api.constants.LevelConstant;
import com.kede.api.except.KedeException;
import com.kede.api.ienum.KedeExceptionEnum;
import com.kede.api.level.domain.SyLevel;
import com.kede.api.level.domain.SyPerm;
import com.kede.api.level.domain.SyUserLevel;
import com.kede.api.level.domain.SyUserSignLog;
import com.kede.api.level.dto.UserIdDto;
import com.kede.api.level.mapper.SyUserLevelMapper;
import com.kede.api.level.service.ISyLevelService;
import com.kede.api.level.service.ISyPermService;
import com.kede.api.level.service.ISyUserLevelService;
import com.kede.api.level.service.SyUserSignLogService;
import com.kede.pojo.ResHttp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Author 乔包包
 * @PackageName server-parent-master
 * @Package com.kede.api.level.service.impl
 * @Date 2024/2/3 10:34
 * @Version 1.0
 */
@Service
public class SyUserLevelServiceImpl extends ServiceImpl<SyUserLevelMapper, SyUserLevel> implements ISyUserLevelService{
    @Autowired
    private ISyLevelService iSyLevelService;
    @Autowired
    private ISyPermService iSyPermService;
    @Autowired
    private SyUserSignLogService syUserSignLogService;
    @Transactional(rollbackFor = {KedeException.class,Exception.class})
    @Override
    public ResHttp getUserLevel(UserIdDto userIdDto) throws KedeException {
        Integer userId = userIdDto.getUserId();
        LambdaQueryWrapper<SyUserLevel> wp = new LambdaQueryWrapper<SyUserLevel>()
                .eq(SyUserLevel::getUserId,userId);
        SyUserLevel one = this.getOne(wp);
        if(ObjectUtil.isNull(one)){//用户没有积分和等级记录
            one = save(userId);
        }
        Integer levelId = one.getLevelId();
        SyLevel level = iSyLevelService.getById(levelId);//当前用户等级
        if(level == null){
            KedeExceptionEnum e = KedeExceptionEnum.DATA_ERR;
            e.setMsgExt("用户等级数据不存在");
            throw new KedeException(e);
        }
        String perm = level.getPerm();
        List<SyPerm> permList = iSyPermService.listAllPerms();
        if(permList.isEmpty()){
            KedeExceptionEnum e = KedeExceptionEnum.DATA_ERR;
            e.setMsgExt("缺少用户权益数据");
            throw new KedeException(e);
        }
        ObjectMapper obm = new ObjectMapper();
        List<Map> permMapList = permList.stream()
                .map(p -> {
                    return obm.convertValue(p, Map.class);
                })
                .collect(Collectors.toList());
        Set<Integer> permIds = new HashSet<>();
        if(StringUtils.isNotBlank(perm)){
            permIds = Arrays.asList(perm.split(","))
                    .stream()
                    .map(s -> {
                        return Integer.valueOf(s);
                    })
                    .collect(Collectors.toSet());
        }
        Set<Integer> finalPermIds = permIds;
        AtomicReference<Integer> lockedCount = new AtomicReference<>(0);
        permMapList = permMapList.stream()
                .map(m->{
                    Integer id = (Integer) m.get("id");
                    if(finalPermIds.contains(id)){
                        m.put(LevelConstant.HAS_PERMISSION,true);
                    }else{
                        m.put(LevelConstant.HAS_PERMISSION,false);
                        lockedCount.getAndSet(lockedCount.get() + 1);
                    }
                    return m;
                }).collect(Collectors.toList());
        Map<String,Object> res = new HashMap<>();
        res.put(LevelConstant.PERMISSION_LIST,permMapList);
        res.put(LevelConstant.LOCKED_PERM,lockedCount.get());
        if(level.getNextId()!=null){
            SyLevel nextLevel = iSyLevelService.getById(level.getNextId());
            res.put(LevelConstant.NEXT_LEVEL,nextLevel);
            res.put(LevelConstant.UPGRADE_SCORE,nextLevel.getScore() - one.getScore());
        }else{
            res.put(LevelConstant.NEXT_LEVEL,null);
            res.put(LevelConstant.UPGRADE_SCORE,0);
        }
        res.put(LevelConstant.CURRENT_SCORE,one.getScore());
        Map<String,Object> currentLevelMap = obm.convertValue(level, Map.class);
        Map<String,Object> data = new HashMap<>();
        data.putAll(currentLevelMap);
        data.putAll(res);
        return ResHttp.ok(data,"ok");

    }

    @Override
    public ResHttp getMission(UserIdDto userIdDto) {
        Integer userId = userIdDto.getUserId();
        LambdaQueryWrapper<SyUserLevel> wp = new LambdaQueryWrapper<SyUserLevel>()
                .eq(SyUserLevel::getUserId,userId);
        SyUserLevel one = this.getOne(wp);
        if(ObjectUtil.isNull(one)){
            one = save(userId);
        }
        Integer levelId = one.getLevelId();//用户等级id
        SyLevel currentLevel = iSyLevelService.getById(levelId);//当前用户等级
        SyLevel nextLevel = null;//下一级
        if(ObjectUtil.isNotNull(currentLevel.getNextId())){
            nextLevel = iSyLevelService.getById(currentLevel.getNextId());
        }
        verifyUserLevel(one, currentLevel, nextLevel);//数据验证
        Map<String, Object> userScore = getUserScore(one, currentLevel, nextLevel);
        //连续7天的签到数据
        List<SyUserSignLog> syUserSignLogs = syUserSignLogService.listPast6Days(userId);


        return null;
    }



    /**
     * 验证用户等级状态及升级
     * @param userLevel 用户当前积分与等级关联数据
     * @param currentLevel 用户当前等级
     * @param nextLevel 用户下一级
     */
    private void verifyUserLevel(SyUserLevel userLevel,SyLevel currentLevel,SyLevel nextLevel){
        Integer score = userLevel.getScore();
        if(currentLevel.getStatus().equals(0)){
            KedeExceptionEnum e = KedeExceptionEnum.DATA_ERR;
            e.setMsgExt("用户当前等级状异常");
            throw new KedeException(e);
        }
        if(ObjectUtil.isNotNull(nextLevel)){
            Integer nextLevelScore = nextLevel.getScore();
            if(score >= nextLevelScore && nextLevel.getStatus().equals(1)){
                userLevel.setLevelId(nextLevel.getId());
                this.save(userLevel);
            }
        }
    }

    /**
     * 获取页面积分公共部分
     * @param userLevel 用户当前积分与等级关联数据
     * @param currentLevel 用户当前等级
     * @param nextLevel 用户下一级

     * @return Map<String,Object>
        {
        "currentScore":int,用户当前积分
        "nextLevel":obj,下一级
        "currentLevel":obj,当前等级
        "nextLevelScore":int,下一级入门分值,
        "currentLevel":obj,当前等级
        "currentLevelScore":int,当前等级入门分值
        "upgradeRate":double #.00 升级百分比 1为满级
        }
     */
    private Map<String,Object> getUserScore(SyUserLevel userLevel,SyLevel currentLevel,SyLevel nextLevel){
        Map<String,Object> res = new HashMap<>();
        res.put(LevelConstant.CURRENT_SCORE,userLevel.getScore());//写入当前用户分值
        if(currentLevel == null){
            KedeExceptionEnum e = KedeExceptionEnum.DATA_ERR;
            e.setMsgExt("用户等级数据不存在");
            throw new KedeException(e);
        }
        Integer nextLevelScore = 0; //下个等级分值
        if(ObjectUtil.isNull(nextLevel)){//用户已经是最高级
            nextLevelScore = null;
            res.put(LevelConstant.NEXT_LEVEL,null);
        }else{//用户不是最高级
            nextLevelScore = nextLevel.getScore();
            res.put(LevelConstant.NEXT_LEVEL,nextLevel);
        }
        if(nextLevelScore.equals(0)){
            KedeExceptionEnum e = KedeExceptionEnum.DATA_ERR;
            e.setMsgExt("升级分数不应为0");
            throw new KedeException(e);
        }
        res.put(LevelConstant.NEXT_LEVEL_SCORE,nextLevelScore);//分值写入
        if(ObjectUtil.isNull(nextLevelScore)){
            res.put(LevelConstant.UPGRADE_RATE,1);
        }else{
            Integer mileage = nextLevelScore - currentLevel.getScore();//升级里程
            Integer scoreWithoutBase = nextLevelScore - userLevel.getScore();
            double rate = (double)scoreWithoutBase/mileage;
            DecimalFormat decimalFormat = new DecimalFormat("#.00");
            String formattedResult = decimalFormat.format(rate);
            res.put(LevelConstant.UPGRADE_RATE,Double.valueOf(formattedResult));
        }
        res.put(LevelConstant.CURRENT_LEVEL,currentLevel);
        res.put(LevelConstant.CURRENT_LEVEL_SCORE,currentLevel.getScore());
        return res;
    }

    /**
     * 保存用户等级
     * @param userId 用户id
     * @return SyUserLevel
     */
    private SyUserLevel save(Integer userId){
        SyLevel lowLevel = iSyLevelService.getLowLevel();
        if(lowLevel == null){
            KedeExceptionEnum e = KedeExceptionEnum.DATA_MISS;
            e.setMsgExt("缺少等级数据");
            throw new KedeException(e);
        }
        SyUserLevel save = new SyUserLevel();
        save.setLevelId(lowLevel.getId());
        save.setScore(0);
        save.setUserId(userId);
        this.save(save);
        LambdaQueryWrapper<SyUserLevel> wp = new LambdaQueryWrapper<SyUserLevel>()
                .eq(SyUserLevel::getUserId,userId);
        return this.getOne(wp);
    }
}
